home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / VirtualDub / vdremote / Main.cpp < prev    next >
C/C++ Source or Header  |  2003-10-01  |  24KB  |  891 lines

  1. #include <crtdbg.h>
  2. #include <objbase.h>
  3.  
  4. #include "clsid.h"
  5. #include "vdremote.h"
  6. #include "vdserver.h"
  7.  
  8. long CAVIFileRemote::gRefCnt = 0;
  9. long CAVIStreamRemote::gRefCnt = 0;
  10.  
  11. ////////////////////////////////////////////////////////////
  12.  
  13. const GUID CDECL CLSID_AVIFile
  14.     = { 0x00020000, 0, 0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  15.  
  16. const GUID CDECL another_IID_IAVIFile
  17.     = { 0x00020020, 0, 0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  18.  
  19. const GUID CDECL another_IID_IAVIStream
  20.     = { 0x00020021, 0, 0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  21.  
  22. const GUID CDECL CLSID_Avisynth
  23.     = { 0xE6D6B700, 0x124D, 0x11D4, 0x86, 0xF3, 0xDB, 0x80, 0xAF, 0xD9, 0x87, 0x78};
  24.  
  25. ////////////////////////////////////////////////////////////
  26.  
  27. BOOL APIENTRY DllMain(HANDLE hModule, ULONG ulReason, LPVOID lpReserved) {
  28.  
  29.     switch(ulReason) {
  30.     case DLL_PROCESS_ATTACH:
  31.         CoInitialize(NULL);
  32.         _RPT0(0,"Process attach\n");
  33.         break;
  34.  
  35.     case DLL_PROCESS_DETACH:
  36.         CoUninitialize();
  37.         _RPT0(0,"Process detach\n");
  38.         break;
  39.     }
  40.  
  41.     return TRUE;
  42. }
  43.  
  44. // WTF:
  45. //    LINK : fatal error LNK1000: unknown error; consult documentation for technical support options
  46. //
  47. // It turns out:
  48. //    VC++ 4 (piece of sh*t) won't link this with Debug info enabled
  49.  
  50. const GUID CDECL CLSID_CAVIFileRemote
  51.     = {0x894288e0,0x0948,0x11d2,{0x81,0x09,0x00,0x48,0x45,0x00,0x0e,0xb5}};
  52. const GUID CDECL CLSID_CAVIStreamRemote
  53.     = {0x91379540,0x0948,0x11d2,{0x81,0x09,0x00,0x48,0x45,0x00,0x0e,0xb5}};
  54.  
  55. // From the Microsoft AVIFile docs.  Dense code...
  56.  
  57. extern "C" STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void **ppv);
  58.  
  59. STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void **ppv) {
  60.     HRESULT hresult;
  61.  
  62.     _RPT0(0,"DllGetClassObject()\n");
  63.  
  64.     if (rclsid == CLSID_CAVIStreamRemote) {
  65.         _RPT0(0,"\tCLSID: CAVIStreamRemote\n");
  66.         hresult = CAVIStreamRemote::Create(rclsid, riid, ppv);
  67.     } else { // if (rclsid == CLSID_CAVIStreamRemote) {
  68.         _RPT0(0,"\tCLSID: CAVIFileRemote (default) \n");
  69.         hresult = CAVIFileRemote::Create(rclsid, riid, ppv);
  70.     }
  71.  
  72.     _RPT0(0,"DllGetClassObject() exit\n");
  73.  
  74.     return hresult;
  75. }
  76.  
  77. extern "C" STDAPI DllCanUnloadNow();
  78.  
  79. STDAPI DllCanUnloadNow() {
  80.     _RPT2(0,"DllCanUnloadNow(): CAVIFileRemote %ld, CAVIStreamRemote %ld\n", CAVIFileRemote::gRefCnt, CAVIStreamRemote::gRefCnt);
  81.  
  82.     return (CAVIFileRemote::gRefCnt || CAVIStreamRemote::gRefCnt) ? S_FALSE : S_OK;
  83. }
  84.  
  85.  
  86. ///////////////////////////////////////////////////////////////////////////
  87. //
  88. //    CAVIFileRemote
  89. //
  90. ///////////////////////////////////////////////////////////////////////////
  91.  
  92.  
  93. HRESULT CAVIFileRemote::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,  void * * ppvObj) {
  94.     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
  95.  
  96.     return Create(CLSID_CAVIFileRemote, riid, ppvObj);
  97. }
  98.  
  99. HRESULT CAVIFileRemote::LockServer (BOOL fLock) {
  100.     _RPT1(0,"%p->CAVIFileRemote::LockServer()\n", this);
  101.     return S_OK;
  102. }
  103.  
  104. STDMETHODIMP CAVIFileRemote::GetClassID(LPCLSID lpClassID) {
  105.     _RPT1(0,"%p->CAVIFileRemote::GetClassID()\n", this);
  106.  
  107.     *lpClassID = CLSID_CAVIFileRemote;
  108.  
  109.     return S_OK;
  110. }
  111.  
  112. STDMETHODIMP CAVIFileRemote::IsDirty() {
  113.     _RPT1(0,"%p->CAVIFileRemote::IsDirty()\n", this);
  114.     return S_FALSE;
  115. }
  116.  
  117. STDMETHODIMP CAVIFileRemote::Load(LPCOLESTR lpszFileName, DWORD grfMode) {
  118.     char filename[MAX_PATH];
  119.  
  120.     _RPT1(0,"%p->CAVIFileRemote::Load()\n", this);
  121.  
  122.     WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, lpszFileName, -1, filename, sizeof filename, NULL, NULL); 
  123.  
  124.     return Open(filename, grfMode, lpszFileName);
  125. }
  126.  
  127. STDMETHODIMP CAVIFileRemote::Save(LPCOLESTR lpszFileName, BOOL fRemember) {
  128.     _RPT1(0,"%p->CAVIFileRemote::Save()\n", this);
  129.     return E_FAIL;
  130. }
  131.  
  132. STDMETHODIMP CAVIFileRemote::SaveCompleted(LPCOLESTR lpszFileName) {
  133.     _RPT1(0,"%p->CAVIFileRemote::SaveCompleted()\n", this);
  134.     return S_OK;
  135. }
  136.  
  137. STDMETHODIMP CAVIFileRemote::GetCurFile(LPOLESTR *lplpszFileName) {
  138.     _RPT1(0,"%p->CAVIFileRemote::GetCurFile()\n", this);
  139.     *lplpszFileName = NULL;
  140.  
  141.     return E_FAIL;
  142. }
  143.  
  144. ///////////////////////////////////////////////////
  145.  
  146. HRESULT CAVIFileRemote::Create(const CLSID& rclsid, const IID& riid, void **ppv) {
  147.     CAVIFileRemote *pAVIFileRemote;
  148.     HRESULT hresult;
  149.  
  150.     _RPT0(0,"CAVIFileRemote::Create()\n");
  151.  
  152.     pAVIFileRemote = new CAVIFileRemote(rclsid);
  153.  
  154.     if (!pAVIFileRemote) return ResultFromScode(E_OUTOFMEMORY);
  155.  
  156.     hresult = pAVIFileRemote->QueryInterface(riid, ppv);
  157.     pAVIFileRemote->Release();
  158.     if (FAILED(GetScode(hresult))) {
  159.         _RPT0(0,"failed!\n");
  160.     }
  161.  
  162.     _RPT0(0,"CAVIFileRemote::Create() exit\n");
  163.  
  164.     return hresult;
  165. }
  166.  
  167. STDMETHODIMP CAVIFileRemote::QueryInterface(const IID& iid, void **ppv) {
  168.     _RPT1(0,"%08lx->CAVIFileRemote::QueryInterface()\n", this);
  169.  
  170.     _RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
  171.     _RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
  172.     _RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
  173.  
  174.     if (iid == IID_IUnknown) {
  175.         *ppv = (IUnknown *)(IAVIFile *)this;
  176.         _RPT0(0,"IUnknown)\n");
  177.     } else if (iid == IID_IClassFactory) {
  178.         *ppv = (IClassFactory *)this;
  179.         _RPT0(0,"IClassFactory)\n");
  180.     } else if (iid == IID_IPersist) {
  181.         *ppv = (IPersist *)this;
  182.         _RPT0(0,"IPersist)\n");
  183.     } else if (iid == IID_IPersistFile) {
  184.         *ppv = (IPersistFile *)this;
  185.         _RPT0(0,"IPersistFile)\n");
  186.     } else if (iid == another_IID_IAVIFile) {
  187.         *ppv = (IAVIFile *)this;
  188.         _RPT0(0,"IAVIFile)\n");
  189.     } else {
  190.         _RPT0(0,"unknown!)\n");
  191.         *ppv = NULL;
  192.         return ResultFromScode(E_NOINTERFACE);
  193.     }
  194.  
  195.     AddRef();
  196.  
  197.     return NULL;
  198. }
  199.  
  200. STDMETHODIMP_(ULONG) CAVIFileRemote::AddRef() {
  201.     _RPT1(0,"%p->CAVIFileRemote::AddRef()\n", this);
  202.     ++gRefCnt;
  203.     return ++m_refs;
  204. }
  205.  
  206. STDMETHODIMP_(ULONG) CAVIFileRemote::Release() {
  207.     _RPT1(0,"%p->CAVIFileRemote::Release()\n", this);
  208.  
  209.     if (!--m_refs)
  210.         delete this;
  211.  
  212.     --gRefCnt;
  213.  
  214.     _RPT0(0,"CAVIFileRemote::Release() exit\n");
  215.  
  216.     return m_refs;
  217. }
  218.  
  219. ///////////////////////////////////////////////////////////////////////////
  220. //
  221. //    CAVIStreamRemote - binding glue
  222. //
  223. ///////////////////////////////////////////////////////////////////////////
  224.  
  225. CAVIStreamClassFactory::CAVIStreamClassFactory(CAVIStreamRemote *af) {
  226.     avifile = af;
  227. }
  228.  
  229. HRESULT CAVIStreamClassFactory::QueryInterface (REFIID riid, void * * ppvObj) {
  230.     return avifile->QueryInterface(riid, ppvObj);
  231. }
  232.  
  233. unsigned long  CAVIStreamClassFactory::AddRef () {
  234.     return avifile->AddRef();
  235. }
  236.  
  237. unsigned long  CAVIStreamClassFactory::Release () {
  238.     return avifile->Release();
  239. }
  240.  
  241. HRESULT CAVIStreamClassFactory::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,  void * * ppvObj) {
  242.     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
  243.  
  244.     return avifile->Create(CLSID_CAVIFileRemote, riid, ppvObj);
  245. }
  246.  
  247. HRESULT CAVIStreamClassFactory::LockServer (BOOL fLock) {
  248.     return S_OK;
  249. }
  250.  
  251. ///////////////////////
  252.  
  253. HRESULT CAVIStreamRemote::Create(const CLSID& rclsid, const IID& riid, void **ppv) {
  254.     CAVIStreamRemote *pAVIStreamRemote;
  255.     IUnknown *pUnknown;
  256.     HRESULT hresult;
  257.  
  258.     _RPT0(0,"CAVIStreamRemote::Create()\n");
  259.  
  260.     pAVIStreamRemote = new CAVIStreamRemote(rclsid, (void **)&pUnknown);
  261.  
  262.     if (!pAVIStreamRemote) return ResultFromScode(E_OUTOFMEMORY);
  263.  
  264.     hresult = pUnknown->QueryInterface(riid, ppv);
  265.     pAVIStreamRemote->Release();
  266.     if (FAILED(GetScode(hresult)))
  267.         _RPT0(0,"Failed!\n");
  268.  
  269.     _RPT0(0,"CAVIStreamRemote::Create() exit\n");
  270.  
  271.     return hresult;
  272. }
  273.  
  274. STDMETHODIMP CAVIStreamRemote::QueryInterface(const IID& iid, void **ppv) {
  275.     _RPT1(0,"%08lx->CAVIStreamRemote::QueryInterface()\n", this);
  276.  
  277.     _RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
  278.     _RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
  279.     _RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
  280.  
  281.     if (iid == IID_IUnknown) {
  282.         *ppv = (IUnknown *)this;
  283.         _RPT0(0,"IUnknown)\n");
  284.     } else if (iid == IID_IClassFactory) {
  285.         *ppv = (IClassFactory *)&iclassfactory;
  286.         _RPT0(0,"IClassFactory)\n");
  287.     } else if (iid == IID_IAVIStream) {
  288.         *ppv = (IAVIStream *)this;
  289.         _RPT0(0,"IAVIStream)\n");
  290.     } else {
  291.         _RPT0(0,"unknown)\n");
  292.         *ppv = NULL;
  293.         return ResultFromScode(E_NOINTERFACE);
  294.     }
  295.  
  296.     AddRef();
  297.  
  298.     return NULL;
  299. }
  300.  
  301. STDMETHODIMP_(ULONG) CAVIStreamRemote::AddRef() {
  302.     _RPT0(0,"CAVIStreamRemote::AddRef()\n");
  303.  
  304.     ++gRefCnt;
  305.     return ++m_refs;
  306. }
  307.  
  308. STDMETHODIMP_(ULONG) CAVIStreamRemote::Release() {
  309.     _RPT0(0,"CAVIStreamRemote::Release()\n");
  310.  
  311.     if (!--m_refs)
  312.         delete this;
  313.  
  314.     --gRefCnt;
  315.  
  316.     _RPT0(0,"CAVIStreamRemote::Release() exit\n");
  317.  
  318.     return m_refs;
  319. }
  320.  
  321. ////////////////////////////////////////////////////////////////////////
  322. //
  323. //        CAVIFileRemote
  324. //
  325. ////////////////////////////////////////////////////////////////////////
  326.  
  327. STDMETHODIMP CAVIFileRemote::CreateStream(PAVISTREAM *ppStream, AVISTREAMINFOW *psi) {
  328.     _RPT1(0,"%p->CAVIFileRemote::CreateStream()\n", this);
  329.  
  330.     if (pafTunnel)
  331.         return pafTunnel->CreateStream(ppStream, psi);
  332.  
  333.     return AVIERR_READONLY;
  334. }
  335.  
  336. STDMETHODIMP CAVIFileRemote::EndRecord() {
  337.     _RPT1(0,"%p->CAVIFileRemote::EndRecord()\n", this);
  338.  
  339.     if (pafTunnel)
  340.         return pafTunnel->EndRecord();
  341.  
  342.     return AVIERR_READONLY;
  343. }
  344.  
  345. STDMETHODIMP CAVIFileRemote::Save(LPCSTR szFile, AVICOMPRESSOPTIONS FAR *lpOptions,
  346.                 AVISAVECALLBACK lpfnCallback) {
  347.     _RPT1(0,"%p->CAVIFileRemote::Save()\n", this);
  348.  
  349.     return AVIERR_READONLY;
  350. }
  351.  
  352. STDMETHODIMP CAVIFileRemote::ReadData(DWORD fcc, LPVOID lp, LONG *lpcb) {
  353.     _RPT1(0,"%p->CAVIFileRemote::ReadData()\n", this);
  354.  
  355.     if (pafTunnel)
  356.         return pafTunnel->ReadData(fcc, lp, lpcb);
  357.  
  358.     return AVIERR_NODATA;
  359. }
  360.  
  361. STDMETHODIMP CAVIFileRemote::WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer) {
  362.     _RPT1(0,"%p->CAVIFileRemote::WriteData()\n", this);
  363.  
  364.     if (pafTunnel)
  365.         return pafTunnel->WriteData(fcc, lpBuffer, cbBuffer);
  366.  
  367.     return AVIERR_READONLY;
  368. }
  369.  
  370. STDMETHODIMP CAVIFileRemote::DeleteStream(DWORD fccType, LONG lParam) {
  371.     _RPT1(0,"%p->CAVIFileRemote::DeleteStream()\n", this);
  372.  
  373.     if (pafTunnel)
  374.         return pafTunnel->DeleteStream(fccType, lParam);
  375.  
  376.     return AVIERR_READONLY;
  377. }
  378.  
  379.  
  380.  
  381.  
  382. CAVIFileRemote::CAVIFileRemote(const CLSID& rclsid) {
  383.     _RPT0(0,"CAVIFileRemote::CAVIFileRemote()\n");
  384.  
  385.     m_refs = 0; AddRef();
  386.  
  387.     szPath = NULL;
  388.     ivdsl = NULL;
  389.     ivdac = NULL;
  390.     vFormat = NULL;
  391.     aFormat = NULL;
  392.     pafTunnel = NULL;
  393.  
  394.     InitializeCriticalSection(&csPort);
  395. }
  396.  
  397. CAVIFileRemote::~CAVIFileRemote() {
  398.     _RPT0(0,"CAVIFileRemote::~CAVIFileRemote()\n");
  399.  
  400.     DeleteCriticalSection(&csPort);
  401.  
  402.     if (ivdac) ivdsl->FrameServerDisconnect(ivdac);
  403.     delete szPath;
  404.  
  405.     if (pafTunnel)
  406.         pafTunnel->Release();
  407. }
  408.  
  409.  
  410. STDMETHODIMP CAVIFileRemote::Open(LPCSTR szFile, UINT mode, LPCOLESTR lpszFileName) {
  411.     HMMIO hmmio = NULL;
  412.     MMCKINFO mmiriff, mmi;
  413.     MMRESULT mmerr;
  414.     HRESULT final = S_OK;
  415.  
  416.     _RPT2(0,"CAVIFileRemote::Open(\"%s\", %08lx)\n", szFile, mode);
  417.  
  418.     if (mode & (OF_CREATE|OF_WRITE)) {
  419.         IPersistFile *ppf;
  420.  
  421.         if (FAILED(CoCreateInstance(CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  422.             return (HRESULT)E_FAIL;
  423.  
  424.         if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  425.             return (HRESULT)E_FAIL;
  426.  
  427.         return (HRESULT)ppf->Load(lpszFileName, mode);
  428.     }
  429.  
  430.     if (!(hmmio = mmioOpen((char *)szFile, NULL, MMIO_READ)))
  431.         return E_FAIL;
  432.  
  433.     _RPT0(0,"File opened.\n");
  434.  
  435.     // RIFF <size> VDRM { PATH <remote-path> }
  436.  
  437.     try {
  438.         char buf[16];
  439.  
  440.         _RPT0(0,"Checking for Avisynth signature...\n");
  441.  
  442.         if (16==mmioRead(hmmio, buf, 16)) {
  443.             buf[9] = 0;
  444.             if (!stricmp(buf, "#avisynth")) {
  445.  
  446.                 mmioClose(hmmio, 0);
  447.  
  448.                 // Hand it off to the Avisynth handler.
  449.  
  450.                 IPersistFile *ppf;
  451.  
  452.                 // Okay, it's not one of our files.  Now try passing it off
  453.                 // to the regular AVI handler!
  454.  
  455.                 _RPT0(0,"Attempt avisynth tunnel create\n");
  456.  
  457.                 if (FAILED(CoCreateInstance(CLSID_Avisynth, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  458.                     return (HRESULT)E_FAIL;
  459.  
  460.                 _RPT0(0,"Attempt avisynth tunnel query -> IPersistFile\n");
  461.  
  462.                 if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  463.                     return (HRESULT)E_FAIL;
  464.  
  465.                 _RPT0(0,"Attempt avisynth tunnel load\n");
  466.  
  467.                 return (HRESULT)ppf->Load(lpszFileName, mode);
  468.             }
  469.         }
  470.  
  471.         mmioSeek(hmmio, 0, SEEK_SET);
  472.  
  473.         _RPT0(0,"Attempting to find 'VDRM'...\n");
  474.  
  475.         mmiriff.fccType = 'MRDV';
  476.         mmerr = mmioDescend(hmmio, &mmiriff, NULL, MMIO_FINDRIFF);
  477.         if (mmerr == MMIOERR_CHUNKNOTFOUND) {
  478.             IPersistFile *ppf;
  479.  
  480.             mmioClose(hmmio, 0);
  481.  
  482.             // Okay, it's not one of our files.  Now try passing it off
  483.             // to the regular AVI handler!
  484.  
  485.             _RPT0(0,"Attempt tunnel create\n");
  486.  
  487.             if (FAILED(CoCreateInstance(CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  488.                 return (HRESULT)E_FAIL;
  489.  
  490.             _RPT0(0,"Attempt tunnel query -> IPersistFile\n");
  491.  
  492.             if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  493.                 return (HRESULT)E_FAIL;
  494.  
  495.             _RPT0(0,"Attempt tunnel load\n");
  496.  
  497.             return (HRESULT)ppf->Load(lpszFileName, mode);
  498.         }
  499.  
  500.         else if (mmerr != MMSYSERR_NOERROR) throw (HRESULT)E_FAIL;
  501.  
  502.         _RPT0(0,"Attempting to find 'PATH'...\n");
  503.         mmi.ckid = 'HTAP';
  504.         mmerr = mmioDescend(hmmio, &mmi, &mmiriff, MMIO_FINDCHUNK);
  505.         if (mmerr == MMIOERR_CHUNKNOTFOUND) throw (HRESULT)E_FAIL;
  506.         else if (mmerr != MMSYSERR_NOERROR) throw (HRESULT)E_FAIL;
  507.  
  508.         _RPT0(0,"Allocate path memory...\n");
  509.         if (!(szPath = new char[mmi.cksize+1]))
  510.             throw (HRESULT)E_OUTOFMEMORY;
  511.  
  512.         szPath[mmi.cksize]=0;
  513.  
  514.         _RPT0(0,"Read in path...\n");
  515.  
  516.         if ((LONG)mmi.cksize != mmioRead(hmmio, szPath, mmi.cksize))
  517.             throw (HRESULT)E_FAIL;
  518.  
  519.         _RPT1(0,"File parsed, remote-path: [%s]\n", szPath);
  520.  
  521.         // now attempt to open the link
  522.  
  523.         ivdsl = GetDubServerInterface();
  524.         if (!ivdsl) throw (HRESULT)E_FAIL;
  525.  
  526.         _RPT0(0,"Have dub server interface.\n");
  527.  
  528.         ivdac = ivdsl->FrameServerConnect(szPath);
  529.         if (!ivdac) throw (HRESULT)E_FAIL;
  530.  
  531.         // retrieve streaminfo and format information
  532.  
  533.         _RPT0(0,"Connected to frameserver.\n");
  534.  
  535.         fHasAudio = ivdac->hasAudio();
  536.  
  537.         _RPT0(0,"Reading video stream info...\n");
  538.  
  539.         if (!ivdac->readStreamInfo(&vStreamInfo, FALSE, &vSampleFirst, &vSampleLast))
  540.             throw (HRESULT)E_FAIL;
  541.  
  542.         _RPT0(0,"Reading video format length...\n");
  543.  
  544.         if ((vFormatLen = ivdac->readFormat(NULL, FALSE))<=0)
  545.             throw (HRESULT)E_FAIL;
  546.  
  547.         _RPT1(0,"Allocating video format (%ld bytes)...\n", vFormatLen);
  548.  
  549.         if (!(vFormat = (BITMAPINFOHEADER *)malloc(vFormatLen)))
  550.             throw (HRESULT)E_OUTOFMEMORY;
  551.  
  552.         _RPT0(0,"Reading video format...\n");
  553.  
  554.         if (ivdac->readFormat(vFormat, FALSE)<=0)
  555.             throw (HRESULT)E_FAIL;
  556.  
  557.         if (fHasAudio) {
  558.             _RPT0(0,"Reading audio stream info...\n");
  559.  
  560.             if (!ivdac->readStreamInfo(&aStreamInfo, TRUE, &aSampleFirst, &aSampleLast))
  561.                 throw (HRESULT)E_FAIL;
  562.  
  563.             _RPT0(0,"Reading audio format length...\n");
  564.  
  565.             if ((aFormatLen = ivdac->readFormat(NULL, TRUE))<=0)
  566.                 throw (HRESULT)E_FAIL;
  567.  
  568.             _RPT1(0,"Allocating audio format (%ld bytes)...\n", aFormatLen);
  569.  
  570.             if (!(aFormat = (WAVEFORMATEX *)malloc(aFormatLen)))
  571.                 throw (HRESULT)E_OUTOFMEMORY;
  572.  
  573.             _RPT0(0,"Reading audio format...\n");
  574.  
  575.             if (ivdac->readFormat(aFormat, TRUE)<=0)
  576.                 throw (HRESULT)E_FAIL;
  577.         }
  578.  
  579.     } catch(HRESULT res) {
  580.         _RPT0(0,"*** failed!\n");
  581.  
  582.         final = res;
  583.     }
  584.  
  585.     if (hmmio) mmioClose(hmmio, 0);
  586.  
  587.     _RPT0(0,"CAVIFileRemote::Open() exit\n");
  588.  
  589.     return final;
  590. }
  591.  
  592. STDMETHODIMP CAVIFileRemote::Info(AVIFILEINFOW *psi, LONG lSize) {
  593.     AVISTREAMINFO *asi;
  594.  
  595.     _RPT0(0,"CAVIFileRemote::Info()\n");
  596.  
  597.     if (pafTunnel)
  598.         return pafTunnel->Info(psi, lSize);
  599.     
  600.     if (!psi || !ivdac) return E_FAIL;
  601.  
  602.     psi->dwMaxBytesPerSec        = 0;
  603.     psi->dwFlags                = AVIFILEINFO_HASINDEX | AVIFILEINFO_ISINTERLEAVED;
  604.     psi->dwCaps                    = AVIFILECAPS_CANREAD | AVIFILECAPS_ALLKEYFRAMES | AVIFILECAPS_NOCOMPRESSION;
  605.     psi->dwStreams                = fHasAudio ? 2 : 1;
  606.     psi->dwSuggestedBufferSize    = 0;
  607.     psi->dwWidth                = vFormat->biWidth;
  608.     psi->dwHeight                = vFormat->biHeight;
  609.     psi->dwEditCount            = 0;
  610.     wcscpy(psi->szFileType, L"VirtualDub Remote AVI");
  611.  
  612.     // determine which stream is longer.
  613.     // v_dwRate / v_dwScale < a_dwRate / a_dwScale
  614.     // v_dwRate * a_dwScale < a_dwRate * v_dwScale
  615.     //
  616.     // DON'T: Panasonic uses AVISTREAMINFO.dwLength as the frame count!
  617.  
  618.     asi = &vStreamInfo;
  619.  
  620. //    if (fHasAudio && vStreamInfo.dwRate * aStreamInfo.dwScale < aStreamInfo.dwRate * vStreamInfo.dwScale)
  621. //        asi = &aStreamInfo;
  622.  
  623.     psi->dwRate                    = asi->dwRate;
  624.     psi->dwScale                = asi->dwScale;
  625.     psi->dwLength                = asi->dwLength;
  626.  
  627.     return 0;
  628. }
  629.  
  630. STDMETHODIMP CAVIFileRemote::GetStream(PAVISTREAM *ppStream, DWORD fccType, LONG lParam) {
  631.     CAVIStreamRemote *casr;
  632.  
  633.     _RPT4(0,"%p->CAVIFileRemote::GetStream(%p, %08lx, %ld)\n", this, ppStream, fccType, lParam);
  634.  
  635.     if (pafTunnel) {
  636.         HRESULT hr;
  637.         hr = pafTunnel->GetStream(ppStream, fccType, lParam);
  638.  
  639.         _RPT2(0,"%08lx %08lx\n", *ppStream, hr);
  640.  
  641.         return hr;
  642.     }
  643.  
  644.     *ppStream = NULL;
  645.  
  646.     if (!fccType) {
  647.         if (lParam==0) fccType = streamtypeVIDEO;
  648.         else if (lParam==1) {
  649.             lParam = 0;
  650.             fccType = streamtypeAUDIO;
  651.         }
  652.     }
  653.  
  654.     if (lParam > 0) return AVIERR_NODATA;
  655.  
  656.     if (fccType == streamtypeVIDEO) {
  657.         if (!(casr = new CAVIStreamRemote(this, FALSE, &vStreamInfo, vFormat, vFormatLen, vSampleFirst, vSampleLast)))
  658.             return AVIERR_MEMORY;
  659.  
  660.         *ppStream = (IAVIStream *)casr;
  661.  
  662.     } else if (fccType == streamtypeAUDIO) {
  663.         if (!fHasAudio) return AVIERR_NODATA;
  664.  
  665.         if (!(casr = new CAVIStreamRemote(this, TRUE, &aStreamInfo, aFormat, aFormatLen, aSampleFirst, aSampleLast)))
  666.             return AVIERR_MEMORY;
  667.  
  668.         *ppStream = (IAVIStream *)casr;
  669.     } else
  670.         return AVIERR_NODATA;
  671.  
  672.     return 0;
  673. }
  674.  
  675.  
  676.  
  677.  
  678.  
  679. void CAVIFileRemote::LockPort() {
  680.     EnterCriticalSection(&csPort);
  681. }
  682.  
  683. void CAVIFileRemote::UnlockPort() {
  684.     LeaveCriticalSection(&csPort);
  685. }
  686.  
  687.  
  688.  
  689. ////////////////////////////////////////////////////////////////////////
  690. //
  691. //        CAVIStreamRemote
  692. //
  693. ////////////////////////////////////////////////////////////////////////
  694.  
  695. STDMETHODIMP CAVIStreamRemote::Create(LONG lParam1, LONG lParam2) {
  696.     _RPT1(0,"%p->CAVIStreamRemote::Create()\n", this);
  697.     return AVIERR_READONLY;
  698. }
  699.  
  700. STDMETHODIMP CAVIStreamRemote::Delete(LONG lStart, LONG lSamples) {
  701.     _RPT1(0,"%p->CAVIStreamRemote::Delete()\n", this);
  702.     return AVIERR_READONLY;
  703. }
  704.  
  705. STDMETHODIMP CAVIStreamRemote::ReadData(DWORD fcc, LPVOID lp, LONG *lpcb) {
  706.     _RPT1(0,"%p->CAVIStreamRemote::ReadData()\n", this);
  707.     return AVIERR_NODATA;
  708. }
  709.  
  710. STDMETHODIMP CAVIStreamRemote::SetFormat(LONG lPos, LPVOID lpFormat, LONG cbFormat) {
  711.     _RPT1(0,"%p->CAVIStreamRemote::SetFormat()\n", this);
  712.     return AVIERR_READONLY;
  713. }
  714.  
  715. STDMETHODIMP CAVIStreamRemote::WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer) {
  716.     _RPT1(0,"%p->CAVIStreamRemote::WriteData()\n", this);
  717.     return AVIERR_READONLY;
  718. }
  719.  
  720. STDMETHODIMP CAVIStreamRemote::SetInfo(AVISTREAMINFOW *psi, LONG lSize) {
  721.     return AVIERR_READONLY;
  722. }
  723.  
  724.  
  725.  
  726. CAVIStreamRemote::CAVIStreamRemote(const CLSID& rclsid, void **pUnknown) : iclassfactory(this) {
  727.     _RPT1(0,"%p->CAVIStreamRemote()\n", this);
  728.     m_refs = 0; AddRef();
  729.  
  730.     parent            = NULL;
  731.     streamInfo        = NULL;
  732.     wfexFormat        = NULL;
  733.     bmihFormat        = NULL;
  734. }
  735.  
  736. CAVIStreamRemote::CAVIStreamRemote(CAVIFileRemote *parentPtr, BOOL isAudio, AVISTREAMINFO *asi, void *format, long format_len, long sample_first, long sample_last) : iclassfactory(this) {
  737.     _RPT2(0,"%p->CAVIStreamRemote(%s)\n", this, isAudio ? "audio" : "video");
  738.     m_refs = 0; AddRef();
  739.  
  740.     parentPtr->AddRef();
  741.  
  742.     parent            = parentPtr;
  743.     fAudio            = isAudio;
  744.     streamInfo        = asi;
  745.     wfexFormat        = (WAVEFORMATEX *)format;
  746.     bmihFormat        = (BITMAPINFOHEADER *)format;
  747.     lFormatLen        = format_len;
  748.     lSampleFirst    = sample_first;
  749.     lSampleLast        = sample_last;
  750. }
  751.  
  752. CAVIStreamRemote::~CAVIStreamRemote() {
  753.     _RPT1(0,"%p->~CAVIStreamRemote()\n", this);
  754.  
  755.     parent->Release();
  756. }
  757.  
  758. STDMETHODIMP_(LONG) CAVIStreamRemote::Info(AVISTREAMINFOW *psi, LONG lSize) {
  759.     AVISTREAMINFOW asiw;
  760.  
  761.     _RPT3(0,"%p->CAVIStreamRemote::Info(%p, %ld)\n", this, psi, lSize);
  762.  
  763.     _RPT1(0,"stream length: %ld\n", streamInfo->dwLength);
  764.     memset(psi, 0, lSize);
  765.     memcpy(&asiw, streamInfo, sizeof(AVISTREAMINFO));
  766.     wcscpy(asiw.szName, fAudio ? L"VDub remote audio #1" : L"VDub remote video #1");
  767.     if (lSize < sizeof(AVISTREAMINFOW)) {
  768.         memcpy(psi, &asiw, lSize);
  769.     } else {
  770.         memcpy(psi, &asiw, sizeof(AVISTREAMINFOW));
  771.     }
  772.  
  773.     return 0;
  774. }
  775.  
  776. STDMETHODIMP_(LONG) CAVIStreamRemote::FindSample(LONG lPos, LONG lFlags) {
  777.     _RPT3(0,"%p->CAVIStreamRemote::FindSample(%ld, %08lx)\n", this, lPos, lFlags);
  778.  
  779.     if (lFlags & FIND_FORMAT)
  780.         return -1;
  781.  
  782.     if (lFlags & FIND_FROM_START)
  783.         return 0;
  784.  
  785.     return lPos;
  786. }
  787.  
  788. STDMETHODIMP CAVIStreamRemote::Read(LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples) {
  789.     HRESULT hres = 0;
  790.     int err;
  791.  
  792.     _RPT3(0,"%p->CAVIStreamRemote::Read(%ld samples at %ld)\n", this, lSamples, lStart);
  793.     _RPT2(0,"\tbuffer: %ld bytes at %p\n", cbBuffer, lpBuffer);
  794.  
  795.     parent->LockPort();
  796.  
  797.     if (plSamples) *plSamples = 0;
  798.     if (plBytes) *plBytes = 0;
  799.  
  800.     // Panasonic does some bad things if you give it fewer samples than it asks for,
  801.     // particularly if cbBuffer is 0 and lpBuffer = NULL.
  802.  
  803.     if (fAudio) {
  804.         LONG lABytes, lASamples;
  805.  
  806.         if (lSamples == AVISTREAMREAD_CONVENIENT)
  807.             lSamples = cbBuffer;
  808.  
  809.             while(lSamples > 0) {
  810.                 err = parent->ivdac->readAudio(lStart, lSamples, lpBuffer, cbBuffer, &lABytes, &lASamples);
  811.  
  812.                 if (err == VDSRVERR_TOOBIG || !lASamples)
  813.                     break;
  814.  
  815.                 if (err != VDSRVERR_OK) {
  816.                     hres = AVIERR_FILEREAD;
  817.                     break;
  818.                 }
  819.  
  820.                 if (plBytes)
  821.                     *plBytes += lABytes;
  822.  
  823.                 if (plSamples)
  824.                     *plSamples += lASamples;
  825.  
  826.                 if (lpBuffer)
  827.                     lpBuffer = (char *)lpBuffer + lABytes;
  828.  
  829.                 cbBuffer -= lABytes;
  830.                 lStart += lASamples;
  831.                 lSamples -= lASamples;
  832.             }
  833.     } else {
  834.         if (lSamples == AVISTREAMREAD_CONVENIENT)
  835.             lSamples = 1;
  836.  
  837.         if (!lpBuffer) {
  838.             if (plSamples) *plSamples = 1;
  839.             if (plBytes) *plBytes = bmihFormat->biSizeImage;
  840.         } else if (cbBuffer < (long)bmihFormat->biSizeImage) {
  841.             _RPT1(0,"\tBuffer too small; should be %ld samples\n", bmihFormat->biSizeImage);
  842.             hres = AVIERR_BUFFERTOOSMALL;
  843.             if (plSamples) *plSamples = 1;
  844.             if (plBytes) *plBytes = bmihFormat->biSizeImage;
  845.         } else {
  846.             _RPT0(0,"\tAttempting to read\n");
  847.             err = parent->ivdac->readVideo(lStart, lpBuffer);
  848.             if (!err) {
  849.                 _RPT0(0,"\tRead successful\n");
  850.                 if (plSamples) *plSamples = 1;
  851.                 if (plBytes) *plBytes = bmihFormat->biSizeImage;
  852.             } else {
  853.                 _RPT0(0,"\tError!\n");
  854.                 hres = AVIERR_FILEREAD;
  855.             }
  856.         }
  857.     }
  858.  
  859.     parent->UnlockPort();
  860.  
  861.     return hres;
  862. }
  863.  
  864. STDMETHODIMP CAVIStreamRemote::ReadFormat(LONG lPos, LPVOID lpFormat, LONG *lpcbFormat) {
  865.     _RPT1(0,"%p->CAVIStreamRemote::ReadFormat()\n", this);
  866.  
  867.     if (!lpFormat) {
  868.         *lpcbFormat = lFormatLen;
  869.         return S_OK;
  870.     }
  871.  
  872.     if (*lpcbFormat < lFormatLen)
  873.         memcpy(lpFormat, wfexFormat, *lpcbFormat);
  874.     else {
  875.         memcpy(lpFormat, wfexFormat, lFormatLen);
  876.         *lpcbFormat = lFormatLen;
  877.     }
  878.  
  879.     return S_OK;
  880. }
  881.  
  882. STDMETHODIMP CAVIStreamRemote::Write(LONG lStart, LONG lSamples, LPVOID lpBuffer,
  883.     LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten, 
  884.     LONG FAR *plBytesWritten) {
  885.  
  886.     _RPT1(0,"%p->CAVIStreamRemote::Write()\n", this);
  887.  
  888.     return AVIERR_READONLY;
  889. }
  890.  
  891.